class SharedMappingList:
    """
    SharedMappingList()
    
    A shared object used by various threads in the HSVO package. Follows a singleton-like
    design pattern that allows implicit sharing of object data amongst many references.
    """
    
    # The actual mapping data structure to be shared across all instances.
    __shared_state = {'mappings': []}
    
    def __init__(self):
        self.__dict__ = self.__shared_state
    
    def addMapping(self, savoir_sessionID, savoirUser, device_sessionID):
        """
        addMapping(savoir_sessionID, savoirUser, device_sessionID) - This method 
        is responsible for adding a new mapping to the shared mapping list.
        """
        
        # Ensure the entry doesn't already exist.
        for mapping in self.mappings:
            if (mapping.savoir_sessionID == savoir_sessionID
                and mapping.savoirUser == savoirUser
                and mapping.device_sessionID == device_sessionID):
                return
        
        # Append the new data to the shared data structure.
        self.mappings.append(Mapping(savoir_sessionID, savoirUser, device_sessionID))
    
    def getMappingBySavoirData(self, savoir_sessionID, savoirUser):
        """
        getMappingBySavoirData(savoir_sessionID, savoirUser) - This method is responsible 
        for returning the mapping with the specified savoir username and session ID.
        """
        
        # Iterate through the shared data structure and return 
        # the mapping that matches both username and sessionID.
        for mapping in self.mappings:
            if (mapping.savoir_sessionID == savoir_sessionID
                and mapping.savoirUser == savoirUser):
                return mapping
    
    def getMappingByDeviceSession(self, device_sessionID):
        """
        getMappingByDeviceSession(savoirUser, device_sessionID) - This method is 
        responsible for returning the mapping with the specified device session ID.
        """
        
        # Iterate through the shared data structure and return 
        # the mapping that matches the device's sessionID.
        for mapping in self.mappings:
            if mapping.device_sessionID == device_sessionID:
                return mapping
    
    def deleteMappingBySavoirData(self, savoir_sessionID, savoirUser):
        """
        deleteMappingBySavoirData(savoir_sessionID, savoirUser) - This method is 
        responsible for deleting the mapping with the specified savoir username 
        and session ID. 
        """
        
        # Iterate through the shared data structure and delete 
        # the mapping that matches both username and sessionID.
        for mapping in self.mappings:
            if (mapping.savoir_sessionID == savoir_sessionID
                and mapping.savoirUser == savoirUser):
                del mapping
    
    def getMappingCount(self):
        """
        getMappingCount() - This method is responsible for returning
        the number of entries currently stored in the mapping list.
        """
        return len(self.mappings)
    
class Mapping:
    """
    Mapping(savoir_sessionID, savoirUser, device_sessionID)
    
    A simple object with three attributes used to map both 
    a SAVOIR username and session ID to a device's session ID.
    """
    
    def __init__(self, savoir_sessionID, savoirUser, device_sessionID):
        self.savoirUser = savoirUser
        self.savoir_sessionID = savoir_sessionID
        self.device_sessionID = device_sessionID